#include "rfid_spi.h"
#include "rfid_api.h"

#if _RFID_FUNCTION_ENABLE_

void RfidPcdWriteReg(uint8_t ucReg, uint8_t ucValue)
{
  RfidWriteRawRC(ucReg, ucValue);
}

uint8_t RfidPcdReadReg(uint8_t ucReg)
{
  return RfidReadRawRC(ucReg);
}

void RfidPcdSetBitMask(uint8_t ucReg, uint8_t ucMask)
{
  uint8_t ucTemp = 0x00;

  ucTemp = RfidPcdReadReg(ucReg);
  RfidPcdWriteReg(ucReg, ucTemp | ucMask);
}

void RfidPcdClearBitMask(uint8_t ucReg, uint8_t ucMask)
{
  uint8_t ucTemp = 0x00;

  ucTemp = RfidPcdReadReg(ucReg);
  RfidPcdWriteReg(ucReg, ucTemp & (~ucMask));
}

void RfidPcdModifyReg(uint8_t ucReg, uint8_t Mask, bool Set)
{
  uint8_t RegValue = 0;

  RegValue = RfidPcdReadReg(ucReg);
  if (Set == true)
  {
    RegValue |= Mask;
  }
  else
  {
    RegValue &= ~Mask;
  }

  RfidPcdSetBitMask(ucReg, RegValue);
}

void RfidPcdReadFifo(uint8_t length, uint8_t *fifo_data)
{
  if (fifo_data != NULL && length != 0)
  {
    for (uint8_t i = 0; i < length; i++)
    {
      fifo_data[i] = RfidPcdReadReg(JREG_FIFODATA);
    }
  }
}

void RfidPcdWriteFifo(uint8_t length, uint8_t *fifo_data)
{
  if (fifo_data != NULL && length != 0)
  {
    for (uint8_t i = 0; i < length; i++)
    {
      RfidPcdWriteReg(JREG_FIFODATA, fifo_data[i]);
    }
  }
}

bool RfidPcdClearFIFO(void)
{
  RfidPcdSetBitMask(JREG_FIFOLEVEL, 0x80);
  if (RfidPcdReadReg(JREG_FIFOLEVEL) == 0)
    return true;

  return false;
}

bool RfidGetFIFODataLenth(uint8_t *FIFOLen, uint8_t *LastBitsLen, uint32_t *pRecBitsLen)
{
  if ((FIFOLen != NULL) && (LastBitsLen != NULL) && (pRecBitsLen != NULL))
  {
    *FIFOLen = RfidPcdReadReg(JREG_FIFOLEVEL);
    *LastBitsLen = RfidPcdReadReg(JREG_CONTROL) & 0x07;

    if (*LastBitsLen)
    {
      *pRecBitsLen = *LastBitsLen;
      if (*FIFOLen > 1)
      {
        *pRecBitsLen += (*FIFOLen - 1) * 8;
      }

      if (*FIFOLen == 0)
      {
        *FIFOLen = 1;
      }
    }
    else
    {
      *pRecBitsLen = (*FIFOLen) * 8;
    }

    return true;
  }

  return false;
}

void RfidSetCW(uint8_t Mode)
{
  RfidPcdSetBitMask(JREG_TXCONTROL, 0x80);

  switch (Mode)
  {
  case TX1_TX2_CW_DISABLE:
  {
    RfidPcdModifyReg(JREG_TXCONTROL, JBIT_TX1RFEN | JBIT_TX2RFEN, false);
    RfidPcdReadReg(JREG_TXCONTROL);
  }
  break;

  case TX1_CW_ENABLE:
  {
    RfidPcdModifyReg(JREG_TXCONTROL, JBIT_TX1RFEN, true);
    RfidPcdModifyReg(JREG_TXCONTROL, JBIT_TX2RFEN, false);
  }
  break;

  case TX2_CW_ENABLE:
  {
    RfidPcdModifyReg(JREG_TXCONTROL, JBIT_TX1RFEN, false);
    RfidPcdModifyReg(JREG_TXCONTROL, JBIT_TX2RFEN, true);
  }
  break;

  case TX1_TX2_CW_ENABLE:
  {
    RfidPcdModifyReg(JREG_TXCONTROL, JBIT_TX1RFEN | JBIT_TX2RFEN, true);
  }
  break;
  }
}

uint8_t RfidReadExtReg(uint8_t RegAddr)
{
  RfidPcdWriteReg(JREG_EXT_REG_ENTRANCE, JBIT_EXT_REG_RD_ADDR + RegAddr);
  return RfidPcdReadReg(JREG_EXT_REG_ENTRANCE);
}

void RfidWriteExtReg(uint8_t RegAddr, uint8_t Regvalue)
{
  RfidPcdWriteReg(JREG_EXT_REG_ENTRANCE, JBIT_EXT_REG_WR_ADDR + RegAddr);
  RfidPcdWriteReg(JREG_EXT_REG_ENTRANCE, JBIT_EXT_REG_WR_DATA + Regvalue);
}

bool RfidPcdSetRf(uint8_t mode)
{
  bool result = false;

  if ((RfidPcdReadReg(JREG_TXCONTROL) & 0x03) == mode)
    return true;

  if (mode == 1)
  {
    RfidPcdClearBitMask(JREG_TXCONTROL, 0x01);
  }
  if (mode == 2)
  {
    RfidPcdClearBitMask(JREG_TXCONTROL, 0x02);
  }
  if (mode == 3)
  {
    RfidPcdSetBitMask(JREG_TXCONTROL, 0x03);
  }
  else
  {
    RfidPcdClearBitMask(JREG_TXCONTROL, 0x03);
  }

  return result;
}

void RfidPcdTxAntOn(void)
{
  uint8_t i;

  i = RfidPcdReadReg(JREG_TXCONTROL);
  if (!(i & 0x03))
  {
    RfidPcdSetBitMask(JREG_TXCONTROL, 0x03);
  }
}

void RfidPcdTxAntOff(void)
{
  RfidPcdClearBitMask(JREG_TXCONTROL, 0x03);
}

uint8_t RfidPcdCommunication(uint8_t Command, uint8_t *pInData, uint8_t InLenByte, uint8_t *pOutData, uint16_t *pOutLenBit)
{
  uint8_t result = 0, rx_temp = 0, rx_len = 0, lastBits = 0, irq = 0;

  if ((pInData != NULL) && (pOutData != NULL) && (pOutLenBit != NULL))
  {
    if ((InLenByte > 0) && (InLenByte <= MAXRLEN))
    {
      *pOutLenBit = 0;

      RfidPcdClearFIFO();
      RfidPcdWriteReg(JREG_COMMAND, JCMD_IDLE);
      RfidPcdWriteReg(JREG_WATERLEVEL, 0x20);
      RfidPcdWriteReg(JREG_COMMIRQ, 0x7F);

      if (Command == JCMD_AUTHENT)
      {
        RfidPcdWriteFifo(InLenByte, pInData);
        RfidPcdSetBitMask(JREG_BITFRAMING, 0x80);
      }

      RfidPcdSetBitMask(JREG_TMODE, 0x80);
      RfidPcdWriteReg(JREG_COMMAND, Command);

      while (1)
      {
        irq = RfidPcdReadReg(JREG_COMMIRQ);
        if (irq & 0x01)
        {
          result = MI_ERR;
          break;
        }

        if (Command == JCMD_AUTHENT)
        {
          if (irq & 0x10)
          {
            result = MI_OK;
            break;
          }
        }

        if (Command == JCMD_TRANSMIT)
        {
          if ((irq & 0x04) && (InLenByte > 0))
          {
            if (InLenByte < 32)
            {
              RfidPcdWriteFifo(InLenByte, pInData);
              InLenByte = 0;
            }
            else
            {
              RfidPcdWriteFifo(32, pInData);
              InLenByte = InLenByte - 32;
              pInData = pInData + 32;
            }

            RfidPcdSetBitMask(JREG_BITFRAMING, 0x80);
            RfidPcdWriteReg(JREG_COMMIRQ, 0x04);
          }

          if ((irq & 0x40) && (InLenByte == 0))
          {
            result = MI_OK;
            break;
          }
        }

        if (Command == JCMD_TRANSCEIVE)
        {
          if ((irq & 0x04) && (InLenByte > 0))
          {
            if (InLenByte > 32)
            {
              RfidPcdWriteFifo(32, pInData);
              InLenByte = InLenByte - 32;
              pInData = pInData + 32;
            }
            else
            {
              RfidPcdWriteFifo(InLenByte, pInData);
              InLenByte = 0;
            }

            RfidPcdSetBitMask(JREG_BITFRAMING, 0x80);
            RfidPcdWriteReg(JREG_COMMIRQ, 0x04);
          }

          if (irq & 0x08)
          {
            if ((irq & 0x40) && (InLenByte == 0) && (RfidPcdReadReg(JREG_FIFOLEVEL) > 32))
            {
              RfidPcdReadFifo(32, pOutData + rx_len);
              rx_len = rx_len + 32;
              RfidPcdWriteReg(JREG_COMMIRQ, 0x08);
            }
          }

          if ((irq & 0x20) && (InLenByte == 0))
          {
            result = MI_OK;
            break;
          }
        }
      }

      if (Command == JCMD_TRANSCEIVE)
      {
        rx_temp = RfidPcdReadReg(JREG_FIFOLEVEL);
        lastBits = RfidPcdReadReg(JREG_CONTROL) & 0x07;
        if ((rx_temp == 0) && (lastBits > 0))
        {
          rx_temp = 1;
        }

        RfidPcdReadFifo(rx_temp, pOutData + rx_len);

        rx_len = rx_len + rx_temp;

        if (lastBits > 0)
        {
          *pOutLenBit = (rx_len - 1) * 8 + lastBits;
        }
        else
        {
          *pOutLenBit = rx_len * 8;
        }
      }

      if (result == MI_OK)
      {
        result = RfidPcdReadReg(JREG_ERROR);
      }

      RfidPcdSetBitMask(JREG_CONTROL, 0x80);
      RfidPcdWriteReg(JREG_COMMAND, JCMD_IDLE);
      RfidPcdClearBitMask(JREG_BITFRAMING, 0x80);
    }
  }

  return result;
}

void RfidCalulateCRC(uint8_t *pDataIn, uint8_t SizeIn, uint8_t *pDataOut)
{
  uint8_t i = 0, Status = 0;

  if ((pDataIn != NULL) && (SizeIn != 0) && (pDataOut != NULL))
  {
    RfidPcdClearBitMask(JREG_DIVIRQ, 0x04);
    RfidPcdWriteReg(JREG_COMMAND, PCD_IDLE);
    RfidPcdSetBitMask(JREG_COMMIRQ, 0x80);
    for (i = 0; i < SizeIn; i++)
    {
      RfidPcdWriteReg(JREG_FIFODATA, pDataIn[i]);
    }
    RfidPcdWriteReg(JREG_COMMAND, PCD_CALCCRC);

    i = 0xFF;
    do
    {
      Status = RfidPcdReadReg(JREG_DIVIRQ);
      i--;
    } while ((i != 0) && !(Status & 0x04));

    pDataOut[0] = RfidPcdReadReg(JREG_CRCRESULT2);
    pDataOut[1] = RfidPcdReadReg(JREG_CRCRESULT1);
  }
}

void RfidPcdSetTimer(uint32_t delaytime)
{
  uint16_t Prescaler = 0;
  uint64_t TimeReload = 0;

  while (Prescaler < 0xFFF)
  {
    TimeReload = ((delaytime * (long)13560) - 1) / (Prescaler * 2 + 1);

    if (TimeReload < 0xFFFF)
      break;

    Prescaler++;
  }

  TimeReload = TimeReload & 0xFFFF;
  RfidPcdSetBitMask(JREG_TMODE, Prescaler >> 8);
  RfidPcdWriteReg(JREG_TPRESCALER, Prescaler & 0xFF);
  RfidPcdWriteReg(JREG_TRELOADHI, TimeReload >> 8);
  RfidPcdWriteReg(JREG_TRELOADLO, TimeReload & 0xFF);
}

uint8_t RfidGetChipVersion(void)
{
  return RfidPcdReadReg(JREG_VERSION);
}

void RfidPcdISOType(char ucType)
{
  if (ucType == 'B')
  {
    RfidPcdWriteReg(JREG_CONTROL, 0x10);
    RfidPcdWriteReg(JREG_TXMODE, 0x83);
    RfidPcdWriteReg(JREG_RXMODE, 0x83);
    RfidPcdWriteReg(JREG_GSN, 0xF4);
    RfidPcdWriteReg(JREG_GSNOFF, 0xF4);
    RfidPcdWriteReg(JREG_TXASK, 0x00);
    RfidPcdWriteReg(JREG_BITFRAMING, 0x00);
  }
  else
  {
    RfidPcdSetBitMask(JREG_CONTROL, 0x10);
    RfidPcdSetBitMask(JREG_TXASK, 0x40);

    RfidPcdWriteReg(JREG_TXMODE, 0x00);
    RfidPcdWriteReg(JREG_RXMODE, 0x00);
    RfidPcdWriteReg(JREG_GSN, 0xF1);
    RfidPcdWriteReg(JREG_CWGSP, 0x3F);
    RfidPcdWriteReg(JREG_MODGSP, 0x01);
    RfidPcdWriteReg(JREG_RFCFG, 0x40);
    RfidPcdWriteReg(JREG_DEMOD, 0x0D);
    RfidPcdWriteReg(JREG_RXTHRESHOLD, 0x84);
    RfidPcdWriteReg(JREG_AUTOTEST, 0x40);
  }
}

void RfidPcdConfig(void)
{
  uint8_t ucRegVal;

  RfidPcdWriteReg(JREG_TPRESCALER, 0x7FF & 0xFF);
  RfidPcdWriteReg(JREG_TMODE, JBIT_TAUTO | ((0x7FF >> 8) & JMASK_TPRESCALER_HI));

  RfidPcdWriteReg(JREG_TRELOADLO, ((uint8_t)(17 & 0xFF)));
  RfidPcdWriteReg(JREG_TRELOADHI, ((uint8_t)((17 >> 8) & 0xFF)));
  RfidPcdSetBitMask(JREG_TXCONTROL, JBIT_TX1RFEN);
  RfidPcdSetBitMask(JREG_CONTROL, JBIT_TSTARTNOW);

  do
  {
    ucRegVal = RfidPcdReadReg(JREG_COMMIRQ);
  } while (!(ucRegVal & JBIT_TIMERI));

  RfidPcdWriteReg(JREG_COMMIRQ, JBIT_TIMERI);
  RfidPcdWriteReg(JREG_COMMAND, JCMD_IDLE);
  RfidPcdWriteReg(JREG_ANALOGTEST, 0xCD);

  RfidPcdWriteReg(JREG_TXSEL, 0x17);

  RfidPcdWriteReg(JREG_FIFOLEVEL, JBIT_FLUSHBUFFER);
  RfidPcdWriteReg(JREG_WATERLEVEL, 16);
  RfidPcdWriteReg(JREG_COMMIRQ, 0x7F);
  RfidPcdWriteReg(JREG_DIVIRQ, 0x7F);
}

bool RfidSoftwareReset(void)
{
  uint16_t RetryCount = 0;

  RfidPcdWriteReg(JREG_COMMAND, JCMD_SOFTRESET);
  RfidPcdSetBitMask(JREG_CONTROL, 0x10);

  while (RfidPcdReadReg(JREG_COMMAND) & 0x10)
  {
    RfidPcdWriteReg(JREG_COMMAND, 0x0F);

    RetryCount++;
    if (RetryCount >= 100)
      return false;

    RfidDelayUs(5);
  }

  return true;
}

void RfidPowerdown(bool En)
{
  (En == true) ? RfidPcdWriteReg(JREG_COMMAND, PCD_SLEEP) : RfidPcdWriteReg(JREG_COMMAND, PCD_IDLE);
}

#endif
